/*
    This file is part of XCOM Mod Manager.

    XCOM Mod Manager is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    XCOM Mod Manager is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with XCOM Mod Manager.  If not, see <http://www.gnu.org/licenses/>.
*/
/* 
 * @author Anthony Surma
 */

import java.security.MessageDigest;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;

final public class Worker implements Runnable 
{           
    final ModInstaller.UPKData upkData;
    final byte[] buffer;
    final int start;
    final int end;
    final MessageDigest md;
    @SuppressWarnings("VolatileArrayField")    
    final CountDownLatch mainCountDownLock;
    final CountDownLatch workerCountDownLock;
    final Thread[] workers;
    volatile byte[] resultBytes = null;
    volatile int resultInt = -1;
        
    Worker(ModInstaller.UPKData upkData, byte[] buffer, int start, int end, MessageDigest md, CountDownLatch mainCountDownLock, CountDownLatch workerCountDownLock, Thread[] workers) 
    {
        this.upkData = upkData;
        this.buffer  = buffer;
        this.start   = start;
        this.end     = end;        
        this.md      = md;        
        this.mainCountDownLock = mainCountDownLock;
        this.workerCountDownLock = workerCountDownLock;
        this.workers = workers;
    }
    @Override
    public void run() 
    {                                  
        final MessageDigest md   = this.md; 
        final int hashDataLength = upkData.searchHashLength;
        final int end            = this.end - hashDataLength;
        final byte[] buffer      = this.buffer;                
        final int targetSum      = upkData.dataSum;
        final byte[] searchHash  = upkData.searchHash;    
             
        for (int j = start; j <= end; ++j)
        {
            final int m = j + hashDataLength;                
            int k = j;                       
            int thisSum = 0;

            while (k < m) thisSum += buffer[k++];

            if (Thread.interrupted()) return;
            
            if (thisSum == targetSum)
            {                
                final byte[] bufferSegment = Arrays.copyOfRange(buffer, j, m);                    
                final byte[] hash = md.digest(bufferSegment);                   

                if (Arrays.equals(hash, searchHash))
                {
                    upkData.isInstalled = true;

                    for (final ModInstaller.ModDiff diff : upkData.diffs) bufferSegment[diff.offset] = diff.data;
                    
                    resultBytes = bufferSegment;                       
                    resultInt   = j;
                    
                    for (Thread t : workers)
                    {
                        if (!Thread.currentThread().equals(t))                           
                        {
                            t.interrupt();
                        }
                    }                                     
                    mainCountDownLock.countDown();                 
                    return;
                }                
                md.reset();
            }               
        }
        
        workerCountDownLock.countDown();
        try 
        {
            workerCountDownLock.await();
        } catch (InterruptedException ex) {}       
        mainCountDownLock.countDown();        
    }    
}
